/*
 * Copyright (C) 2014 Realtek Semiconductor Corp.
 * All Rights Reserved.
 *
 * This program is the proprietary software of Realtek Semiconductor
 * Corporation and/or its licensors, and only be used, duplicated,
 * modified or distributed under the authorized license from Realtek.
 *
 * ANY USE OF THE SOFTWARE OTHER THAN AS AUTHORIZED UNDER
 * THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
 *
 * Purpose : Definition of OMCI MIB APIs
 *
 * Feature : The file includes the following modules and sub-modules
 *           (1) OMCI MIC APIs
 */

#include "app_basic.h"
#include "util_aes.h"
#include "omci_mic.h"
#include "omci_driver.h"

unsigned char omci_msk[OMCI_MSK_LEN] = {0};


unsigned char omci_def_msk_key[16] =
{
    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
    0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55
};


unsigned char omci_sk_string[OMCI_SK_STR_LEN] = 
{
    0x53, 0x65, 0x73, 0x73, 
    0x69, 0x6f, 0x6e, 0x4b
};/*"SessionK"*/


unsigned char omci_ik_msg[OMCI_IK_MSG_LEN] =
{
    0x4f, 0x4d, 0x43, 0x49, 0x49, 0x6e, 0x74, 0x65,
    0x67, 0x72, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79
};/*"OMCIIntegrityKey"*/

void _print_hex(uint8_t *buf, int32_t len)
{
	int32_t i;
	for(i = 0; i < len; i++) {
		printf("%02x", buf[i]);
		if((i % 4) == 3) 
			printf(" ");
		if((i % 16) == 15) 
			printf("\n");    
	}
	printf("\n");
}

int omci_gen_msk(unsigned char *gponPwd, unsigned char *msk)
{
    if (aes128_cmac_compute(omci_def_msk_key, gponPwd, OMCI_ONU_REG_ID_LEN, OMCI_MSK_LEN, msk))
    {
        OMCI_LOG (OMCI_LOG_LEVEL_ERR, "Failed to calculate the MSK\n");
        return -1;
    }

    return 0;
}

//void omci_update_omci_msk(unsigned char *pMsk)
//{
//    memcpy(omci_msk, pMsk, OMCI_MSK_LEN);
//    omci_gen_omci_ik();
//}

GOS_ERROR_CODE omci_gen_sk(unsigned char *msk, unsigned char *sn, unsigned char *ponTag, unsigned char *sk)
{
    unsigned char *pMsg                    = NULL;

    pMsg = (unsigned char *)malloc(OMCI_SK_MSG_LEN);
    if (NULL == pMsg)
    {
        OMCI_LOG (OMCI_LOG_LEVEL_ERR, "Failed to malloc\n");
        return GOS_ERR_SYS_CALL_FAIL;
    }

    memset(pMsg, 0, OMCI_SK_MSG_LEN);
    memcpy(pMsg, sn, OMCI_SN_LEN);
    memcpy((pMsg + OMCI_SN_LEN), ponTag, OMCI_PON_TAG_LEN);
    memcpy((pMsg + OMCI_SN_LEN + OMCI_PON_TAG_LEN), omci_sk_string, OMCI_SK_STR_LEN);

    _print_hex(pMsg, OMCI_SK_MSG_LEN);

    if (GOS_OK != aes128_cmac_compute(msk, pMsg, OMCI_SK_MSG_LEN, OMCI_SK_LEN, sk))
    {
         OMCI_LOG (OMCI_LOG_LEVEL_ERR, "Failed to calculate the SK\n");
        free(pMsg);
        return GOS_ERR_PARAM;
    }

    free(pMsg);
    return GOS_OK;
}


int omci_gen_omci_ik(unsigned char *msk, unsigned char *sn, unsigned char *ponTag, unsigned char *omci_ik)
{
    unsigned char sk[OMCI_SK_LEN] = {0};
    
    if (GOS_OK != omci_gen_sk(msk, sn, ponTag, sk))
    {
        OMCI_LOG (OMCI_LOG_LEVEL_ERR, "Failed to calculate the SK\n");
        return -1;
    }

    if (GOS_OK != aes128_cmac_compute(sk, omci_ik_msg, OMCI_IK_MSG_LEN, OMCI_IK_LEN, omci_ik))
    {
        OMCI_LOG (OMCI_LOG_LEVEL_ERR, "Failed to calculate the OMCI_IK\n");
        return -1;
    }

    return 0;
}

void omci_mic_init(unsigned char *sn, unsigned char *gponPwd, unsigned char *ponTag, unsigned char *omciIk)
{
    unsigned char omciMsk[OMCI_MSK_LEN];

    //generate default MSK
    omci_gen_msk(gponPwd, omciMsk);

    //generate default OMCI IK
    omci_gen_omci_ik(omciMsk, sn, ponTag, omciIk);

}

